#pragma once
#include <Windows.h>
#include "Declarations.h"
#include "dt_recv2.h"
#include "Utilities.h"
#include "ChecksumCRC.h"
#include "IClientRenderable.h"
#include "Entity.h"
//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
// VTable Indexes

//////////////////////////////////////////////////////////////////////////
/// SDKStructs


struct Ray_t
{
	__declspec(align(16)) SD_Tools::Vector4 m_Start;				// starting point, centered within the extents
	__declspec(align(16)) SD_Tools::Vector4 m_Delta;				// direction + length of the ray
	__declspec(align(16)) SD_Tools::Vector4 m_StartOffset;		// Add this to m_Start to get the actual ray start
	__declspec(align(16)) SD_Tools::Vector4 m_Extents;			// Describes an axis aligned box extruded along a ray
	bool m_IsRay;												// are the extents zero?
	bool m_IsSwept;												// is delta != 0?
	
	void Init( SD_Tools::Vector& start, SD_Tools::Vector& end )
	{
		/*m_Delta = SD_Tools::MathHelper::SubVector(start, end);

		m_IsSwept = (m_Delta.MagnitudeSqr() != 0.0f);

		
		m_Extents.Clear();
		m_IsRay = true;

		// Offset m_Start to be in the center of the box...
		m_StartOffset.Clear();
		m_Start = start;*/

		m_Delta.x = start.x - end.x;
		m_Delta.y = start.y - end.y;
		m_Delta.z = start.z - end.z;
		m_Delta.w = 0.0f;

		m_IsSwept = (((m_Delta.x*m_Delta.x)+(m_Delta.y*m_Delta.y)+(m_Delta.z*m_Delta.z)) != 0.0f);
		m_Extents.x = m_Extents.y = m_Extents.z = m_Extents.w = 0.0f;

		m_IsRay = true;

		m_Start.x = start.x;
		m_Start.y = start.y;
		m_Start.z = start.z;
		m_Start.w = 0.0f;
	}
};



struct player_info_t
{
	char			name[32];
	int				userID;
	char			guid[32 + 1];
	unsigned int	friendsID;
	char			friendsName[32];
	bool			fakeplayer;
	bool			ishltv;
	unsigned long	customFiles[4];
	unsigned char	filesDownloaded;
};

struct VMatrix
{
	union
	{
		struct
		{
			float x1;
			float x2;
			float x3;
			float x4;
			float y1;
			float y2;
			float y3;
			float y4;
			float z1;
			float z2;
			float z3;
			float z4;
			float w1;
			float w2;
			float w3;
			float w4;
		};
		float data[4][4];
	};
};

struct BoneVector
{
	float x2;
	float x3;
	float x4;
	float x;
	float y2;
	float y3;
	float y4;
	float y;
	float z2;
	float z3;
	float z4;
	float z;
};

struct BonePtr
{
	BoneVector Bones[50];
};

struct RadarPlayer
{
	DWORD ID;							// 0x0 
	DWORD Userid;						// 0x4 User ID on Server
	DWORD Icon;							// 0x8 Texture Icon ID
	DWORD TeamColor;					// 0xc 
	BYTE Name[32];						// 0x10 
	DWORD Team;							// 0x30 
	DWORD Hp;							// 0x34 
	SD_Tools::Vector Position;			// 0x38 
	SD_Tools::Angle Viewangle;			// 0x44 
	SD_Tools::Vector2 History[30];	// 0x50 
};

struct RadarClass
{
	BYTE Unknown[0x144];
	RadarPlayer Players[32];
};

struct ModelStringStruct
{
	BYTE Unknown[0x14];
	char ModelString[32];
};



struct cplane_t
{
	SD_Tools::Vector	normal;
	float	dist;
	byte	type;			
	byte	signbits;		
	byte	pad[2];
};

struct csurface_t
{
	const char*		name;
	short			surfaceProps;
	unsigned short	flags;
};

class CUserCmd
{
public:
	CUserCmd()
	{
		Reset();
	}

	virtual ~CUserCmd() { };

	void Reset()
	{
		command_number = 0;
		tick_count = 0;
		viewangles.Clear();
		forwardmove = 0.0f;
		sidemove = 0.0f;
		upmove = 0.0f;
		buttons = 0;
		impulse = 0;
		weaponselect = 0;
		weaponsubtype = 0;
		random_seed = 0;
		mousedx = 0;
		mousedy = 0;

		hasbeenpredicted = false;
	}

	CUserCmd& operator =( const CUserCmd& src )
	{
		if ( this == &src )
			return *this;

		command_number		= src.command_number;
		tick_count			= src.tick_count;
		viewangles			= src.viewangles;
		forwardmove			= src.forwardmove;
		sidemove			= src.sidemove;
		upmove				= src.upmove;
		buttons				= src.buttons;
		impulse				= src.impulse;
		weaponselect		= src.weaponselect;
		weaponsubtype		= src.weaponsubtype;
		random_seed			= src.random_seed;
		mousedx				= src.mousedx;
		mousedy				= src.mousedy;

		hasbeenpredicted	= src.hasbeenpredicted;
		return *this;
	}

	CUserCmd( const CUserCmd& src )
	{
		*this = src;
	}

	CRC32_t GetChecksum( void ) const
	{
		CRC32_t crc;

		CRC32_Init( &crc );
		CRC32_ProcessBuffer( &crc, &command_number, sizeof( command_number ) );
		CRC32_ProcessBuffer( &crc, &tick_count, sizeof( tick_count ) );
		CRC32_ProcessBuffer( &crc, &viewangles, sizeof( viewangles ) );    
		CRC32_ProcessBuffer( &crc, &forwardmove, sizeof( forwardmove ) );   
		CRC32_ProcessBuffer( &crc, &sidemove, sizeof( sidemove ) );      
		CRC32_ProcessBuffer( &crc, &upmove, sizeof( upmove ) );         
		CRC32_ProcessBuffer( &crc, &buttons, sizeof( buttons ) );		
		CRC32_ProcessBuffer( &crc, &impulse, sizeof( impulse ) );        
		CRC32_ProcessBuffer( &crc, &weaponselect, sizeof( weaponselect ) );	
		CRC32_ProcessBuffer( &crc, &weaponsubtype, sizeof( weaponsubtype ) );
		CRC32_ProcessBuffer( &crc, &random_seed, sizeof( random_seed ) );
		CRC32_ProcessBuffer( &crc, &mousedx, sizeof( mousedx ) );
		CRC32_ProcessBuffer( &crc, &mousedy, sizeof( mousedy ) );
		CRC32_Final( &crc );

		return crc;
	}

	// For matching server and client commands for debugging
	int		command_number;

	// the tick the client created this command
	int		tick_count;

	// Player instantaneous view angles.
	SD_Tools::Angle	viewangles;     
	// Intended velocities
	//	forward velocity.
	float	forwardmove;   
	//  sideways velocity.
	float	sidemove;      
	//  upward velocity.
	float	upmove;         
	// Attack button states
	int		buttons;		
	// Impulse command issued.
	BYTE    impulse;        
	// Current weapon id
	int		weaponselect;	
	int		weaponsubtype;

	int		random_seed;	// For shared random functions

	short	mousedx;		// mouse accum in x from create move
	short	mousedy;		// mouse accum in y from create move

	// Client only, tracks whether we've predicted this command at least once
	bool	hasbeenpredicted;

};

typedef DWORD CRC32_t;

class CVerifiedUserCmd
{
public:
	CUserCmd	m_cmd;
	CRC32_t		m_crc;
};


class CInput
{
public:
	virtual void f0000();
	virtual void f0001();
	virtual void f0002();
	virtual void f0003();
	virtual void f0004();
	virtual void f0005();
	virtual void f0006();
	virtual void f0007();
	virtual CUserCmd* GetUserCmd(int sequence_number);
};

class CGlobalVarsBase
{
public:
	
	float			realtime;
	int				framecount;
	float			absoluteframetime;
	float			curtime;
	float			frametime;
	int				maxClients;
	int				tickcount;
	float			interval_per_tick;
	float			interpolation_amount;
	int				simTicksThisFrame;
	int				network_protocol;	
};

#define	MAX_EDICT_BITS			11
#define NUM_ENT_ENTRY_BITS		(MAX_EDICT_BITS + 1)
#define NUM_ENT_ENTRIES			(1 << NUM_ENT_ENTRY_BITS)
#define ENT_ENTRY_MASK			(NUM_ENT_ENTRIES - 1)

class CBaseHandle
{
public:
	int GetEntryIndex()
	{
		return m_Index & ENT_ENTRY_MASK;
	}

protected:

	unsigned long	m_Index;
};

class IClientEntityList
{
public:
	// Get IClientNetworkable interface for specified entity
	virtual /*IClientNetworkable*/DWORD	GetClientNetworkable( int entnum ) = 0;
	virtual /*IClientNetworkable*/DWORD	GetClientNetworkableFromHandle( /*CBaseHandle*/LPVOID hEnt ) = 0;
	virtual /*IClientUnknown*/DWORD		GetClientUnknownFromHandle( /*CBaseHandle*/LPVOID hEnt ) = 0;

	// NOTE: This function is only a convenience wrapper.
	// It returns GetClientNetworkable( entnum )->GetIClientEntity().
	virtual Entity*		GetClientEntity( int entnum ) = 0;
	virtual Entity*		GetClientEntityFromHandle( /*CBaseHandle*//*LPVOID*/CBaseHandle hEnt ) = 0;

	// Returns number of entities currently in use
	virtual int					NumberOfEntities( bool bIncludeNonNetworkable ) = 0;

	// Returns highest index actually used
	virtual int					GetHighestEntityIndex( void ) = 0;

};

class IVEngineClient
{
public:
	virtual void f0000();
	virtual void f0001();
	virtual void f0002();
	virtual void f0003();
	virtual void f0004();
	virtual void GetScreenSize(int &width, int &height);
	virtual void ServerCmd( const char *szCmdString, bool bReliable = true );
	virtual void ClientCmd( const char *szCmdString );
	virtual bool GetPlayerInfo( int ent_num, player_info_t *pinfo );
	virtual void f0009();
	virtual void f0010();
	virtual void f0011();
	virtual int GetLocalPlayer();
	virtual void f0013();
	virtual void f0014();
	virtual void f0015();
	virtual void f0016();
	virtual void f0017();
	virtual void f0018();
	virtual void GetViewAngles(SD_Tools::Angle& va);
	virtual void SetViewAngles(SD_Tools::Angle& va);
	virtual int GetMaxClients();
	virtual void f0022();
	virtual void f0023();
	virtual void f0024();
	virtual void f0025();
	virtual bool IsInGame();
	virtual bool IsConnected();
	virtual void f0028();
	virtual void f0029();
	virtual void f0030();
	virtual void f0031();
	virtual void f0032();
	virtual void f0033();
	virtual void f0034();
	virtual void f0035();
	virtual VMatrix& WorldToScreenMatrix();
};

class IEngineTrace
{
public:
	virtual void            func0();                                    //0x0000(0)
	virtual void            func1();                                    //0x0004(1)
	virtual void            func2();                                    //0x0008(2)
	virtual void            func3();                                    //0x000C(3)
	//virtual void            func4();                                    //0x000C(3)
	virtual void            TraceRay(const Ray_t &ray, UINT fMask, void* pTraceFilter, trace_t* pTrace);
};//size: 0x4(4)

struct ClientClass
{
	void*			m_pCreateFn;
	void*			m_pCreateEventFn;
	char			*m_pNetworkName;
	RecvTable		*m_pRecvTable;
	ClientClass		*m_pNext;
	int				m_ClassID;
};

class IBaseClientDLL
{
public:
	virtual int				func0() = 0;
	virtual void			func1() = 0;
	virtual void			func2() = 0;
	virtual void            func3() = 0;
	virtual void            func4() = 0;
	virtual void			func5() = 0;
	virtual void			func6() = 0;
	virtual void			func7( void ) = 0;
	virtual ClientClass		*GetAllClasses( void ) = 0;
	virtual int				func9() = 0;
	virtual void			func10() = 0;
	virtual void			func11() = 0;
	virtual void			func12() = 0;
	virtual void			func13() = 0;
	virtual void			func14() = 0;
	virtual void			func15() = 0;
	virtual void			func16() = 0;
	virtual void			func17() = 0;
	virtual bool			func18() = 0;
	virtual int				func19() = 0;
	virtual void            func20();
	virtual void			CreateMove ( int sequence_number, float input_sample_frametime, bool active ) = 0;	
};

class CBaseCombatWeapon
{
public:
	int GetWeaponId()
	{
		typedef int (__thiscall* GetWeaponId_t)(void* pThis);
		GetWeaponId_t m_GetWeaponId=(GetWeaponId_t)((*(PDWORD*)this)[366]);
		return m_GetWeaponId(this);
	}

	float GetSpread()
	{
		typedef float (__thiscall* GetSpread_t)(void* pThis);
		GetSpread_t m_GetSpread=(GetSpread_t)((*(PDWORD*)this)[377]);
		return m_GetSpread(this);
	}

	float GetInaccuracy()
	{
		typedef float (__thiscall* GetInaccuracy_t)(void* pThis);
		GetInaccuracy_t m_GetInaccuracy=(GetInaccuracy_t)((*(PDWORD*)this)[378]);
		return m_GetInaccuracy(this);
	}

	void UpdateAccuracyPenalty()
	{
		typedef void (__thiscall* UpdateAccuracyPenalty_t)(void* pThis);
		UpdateAccuracyPenalty_t m_UpdateAccuracyPenalty = (UpdateAccuracyPenalty_t)((*(PDWORD*)this)[379]);
		return m_UpdateAccuracyPenalty(this);
	} 
};

//////////////////////////////////////////////////////////////////////////
